classdef C_Rx < handle
    %C_RX Summary of this class goes here
    %   Detailed explanation goes here
    
    properties (GetAccess= ?C_Eval, SetAccess='private')
        Param;
        
        Amplitude;       
        FFTsize;
        GI_size;
        reshapeDimension;
        
        RxDataBin;
        RxDataDec;
        RawRxSignal;
        RawConstellation;
        EqualisedConstellation;
        
        Constellation;
        ChObj;
        TxObj;
    end    
    
    properties (Constant)
    
    end
    
    methods
        function this = C_Rx(TxObj, ChObj)
            this.Constellation = C_constellation.Instance;
            this.TxObj = TxObj;
            this.ChObj = ChObj;
        end
        
        function Initialise(this, param)
            this.Param = param;
            this.FFTsize = this.TxObj.Param.numSubcarriers*2;
            this.GI_size = this.TxObj.GI_size;
            
            this.Amplitude = 1/sqrt(2/(this.FFTsize/this.Param.Fs));
            this.RxDataBin = zeros(length(this.ChObj.Param.EbPerNo), this.TxObj.TxDataSize);
            this.RxDataDec = zeros(length(this.ChObj.Param.EbPerNo), this.TxObj.TxDataSize / log2(this.TxObj.M));
            this.RawRxSignal = zeros(this.TxObj.sigSize(1), this.TxObj.sigSize(2), length(this.ChObj.Param.EbPerNo));
            this.reshapeDimension = [this.FFTsize + this.GI_size, this.TxObj.Param.numOfdmBlocks, length(this.ChObj.Param.EbPerNo)];
            this.RawConstellation = zeros(this.reshapeDimension);
            this.EqualisedConstellation = zeros(this.reshapeDimension);
        end
        
        function Decode(this, Signal)
            this.RawRxSignal = Signal;       
            this.RawConstellation = fft(Signal(1:this.FFTsize,:,:));                   
            ZF_EQ(this);                                                                                           
%             [BinData, DecData] = this.Constellation.GetData(this.Constellation, this.EqualisedConstellation(this.TxObj.Param.ActiveModBand,:,:), this.Param.ActiveModType);
            [BinData, DecData] = this.Constellation.GetData(this.Constellation, this.EqualisedConstellation(this.TxObj.Param.ActiveModBand,:,:), this.Param.ActiveModType);
            
            this.RxDataBin = reshape(BinData, this.TxObj.TxDataSize, length(this.ChObj.Param.EbPerNo))';
            this.RxDataDec = reshape(DecData, this.TxObj.TxDataSize / log2(this.TxObj.M), length(this.ChObj.Param.EbPerNo))';
        end
    end  
end

function ZF_EQ(this)
    RxPilots = this.RawConstellation(this.TxObj.Param.PilotModBand,:,:);
    OriPilots = repmat(this.TxObj.Symbols(this.TxObj.Param.PilotModBand,:), [1, 1, length(this.ChObj.Param.EbPerNo)]);
    
    est_H = RxPilots ./ OriPilots;
    inv_H = 1 ./ est_H;
    intpInv_H = interp1( this.TxObj.Param.PilotModBand, inv_H, 1:this.TxObj.Param.numSubcarriers, 'linear', 'extrap');
    this.EqualisedConstellation = this.RawConstellation(1:this.TxObj.Param.numSubcarriers, :, :) .* intpInv_H;
    
%-----------------------------------------------------------------------------------------------------------------------------------  

%     % test code   
%     figure(1); hold on;
%     plot([1:this.TxObj.Param.numSubcarriers*2]*this.TxObj.Param.Fs, abs(fft(this.ChObj.ChIR, this.TxObj.Param.numSubcarriers*2)));
%     plot(this.TxObj.Param.PilotModBand*this.TxObj.Param.Fs, abs(est_H), 'r*');
%     plot([1:this.TxObj.Param.numSubcarriers]*this.TxObj.Param.Fs, abs(intpInv_H), 'gv');    
%     xlabel('frequency'); ylabel('magnitude'); title('Channel freq response');
% %     legend('Channel freq response', 'estimated response using pilot (no AWGN)');
    
%     figure(2); hold on;
%     plot([1:this.TxObj.Param.numSubcarriers*2]*this.TxObj.Param.Fs, angle(fft(this.ChObj.ChIR, this.TxObj.Param.numSubcarriers*2)));
%     plot(this.TxObj.Param.PilotModBand*this.TxObj.Param.Fs, angle(est_H), 'r*');
%     plot([1:this.TxObj.Param.numSubcarriers]*this.TxObj.Param.Fs, angle(intpInv_H), 'gv');
%     xlabel('frequency'); ylabel('magnitude'); title('Channel phase response');
%     legend('Channel phase response', 'estimated response using pilot (no AWGN)');
%     
%     figure(3); hold on;
%     plot(OriPilots, '+');
%     plot(RxPilots, 'r.');
%     title('constellation diagram');
%     legend('original pilot', 'received pilot (no AWGN)');
%     
%     figure(4); hold on;
%     plot(this.TxObj.Symbols(this.TxObj.Param.ActiveModBand',:,:), '+');
%     plot(this.RawConstellation(1:this.TxObj.Param.numSubcarriers, :, :), 'r.');
%     plot(this.EqualisedConstellation, 'gv');
%     title('constellation diagram');
%     legend('original data', 'received data (no AWGN)');
    
    H = fft(this.ChObj.ChIR, this.TxObj.Param.numSubcarriers*2);
    intp_H = interp1( this.TxObj.Param.PilotModBand, est_H, 1:this.TxObj.Param.numSubcarriers, 'linear', 'extrap');
    intp_H = permute(intp_H, [1 3 2]);
    intp_H = [intp_H; zeros(1,size(intp_H,2)) ;conj(flipud(intp_H(2:end,:)))];
%     corr_H = intpInv_H.' .* H(1:this.TxObj.Param.numSubcarriers);
    H_err = repmat(H.', [1,length(this.ChObj.Param.EbPerNo)]) - intp_H;
    estIntp_h = ifft(intp_H);
    h_err = repmat(this.ChObj.ChIR.', [1,length(this.ChObj.Param.EbPerNo)]) - real(estIntp_h(1:length(this.ChObj.ChIR),:));
    
%     figure(5); hold on; 
%     plot(abs(corr_H));
%     
%     figure(6); hold on; 
%     plot(unwrap(angle(corr_H)));
%     
%     figure(7); hold on; 
%     plot(abs(ifft(corr_H)));
%     
%     figure(8); hold on; 
%     plot(angle(ifft(corr_H)));
%     
%     mean(abs(1 - abs(corr_H)))
%     mean(abs(0 - angle(corr_H)))

%     figure(9); hold on;    
%     plot(1:this.TxObj.Param.numSubcarriers, unwrap(angle(intpInv_H(:,1,1))));
%     plot(this.TxObj.Param.PilotModBand, unwrap(angle(inv_H(:,1,1))),'g');
%     plot(1:this.TxObj.Param.numSubcarriers, angle(intpInv_H(:,1,1)),'m');
%     plot(this.TxObj.Param.PilotModBand, angle(inv_H(:,1,1)),'r');
    
%     figure(10); hold on;
%     plot(unwrap(angle(this.RawConstellation(1:this.TxObj.Param.numSubcarriers, 1, 1))));
%     plot(unwrap(angle(intpInv_H(:,1,1))),'r');
%     plot(unwrap(angle(this.EqualisedConstellation(:,1,1))),'g');

%     for i=1:size(est_H,3)
%         figure(1100+i); hold all;
%         semilogy(abs(H));
%         semilogy(abs(intp_H(:,1,i)));
%     end    
    
    figure(12); hold all;
%     waterfall((10*log10(abs(H_err))).');
    semilogy([0:this.TxObj.Param.numSubcarriers*2-1]*(this.TxObj.Param.Fs/(this.TxObj.Param.numSubcarriers*2)), abs(H_err))
    grid on
    
    figure(13); hold all;
%     waterfall((10*log10(abs(h_err))).');
    semilogy([0:length(this.ChObj.ChIR)-1]*(1/this.TxObj.Param.Fs), abs(h_err));
    grid on

end

function MMSE_EQ(this)
%     F = dftmtx(this.TxObj.Param.numSubcarriers);
%     V = sqrt(this.TxObj.Param.numSubcarriers) * F(:, 1:this.TxObj.GI_size);
%     RxPilots = zeros(1:this.TxObj.Param.numSubcarriers, this.TxObj.Param.numOfdmBlocks, length(this.ChObj.Param.EbPerNo));
%     OriPilots = zeros(1:this.TxObj.Param.numSubcarriers, this.TxObj.Param.numOfdmBlocks, length(this.ChObj.Param.EbPerNo));
% 
%     RxPilots(this.TxObj.Param.PilotModBand,:,:) = this.RawConstellation(this.TxObj.Param.PilotModBand,:,:);
%     OriPilots(this.TxObj.Param.PilotModBand,:,:) = repmat(this.TxObj.Symbols(this.TxObj.Param.PilotModBand,:), [1, 1, length(this.ChObj.Param.EbPerNo)]);
    
    
end

function SigOut = addTimingOffset(this, SigIn)
    SigOut=[];                                         
        for i=1:length(SigIn)-1
            y = pchip( [1 2], SigIn(i:i+1), 1:1/100:2);
            SigOut = [SigOut y(1 + this.Param.ToffsetPct)];
        end
end


